home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / ghview15.gz / ghostview-1.5.tar / ghostview-1.5 / misc.c < prev    next >
C/C++ Source or Header  |  1993-07-23  |  36KB  |  1,308 lines

  1. /*
  2.  * misc.c -- Everything that isn't a callback or action.
  3.  * Copyright (C) 1992  Timothy O. Theisen
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *   Author: Tim Theisen           Systems Programmer
  20.  * Internet: tim@cs.wisc.edu       Department of Computer Sciences
  21.  *     UUCP: uwvax!tim             University of Wisconsin-Madison
  22.  *    Phone: (608)262-0438         1210 West Dayton Street
  23.  *      FAX: (608)262-9777         Madison, WI   53706
  24.  */
  25.  
  26. #include <stdio.h>
  27. #ifndef SEEK_SET
  28. #define SEEK_SET 0
  29. #endif
  30.  
  31. #include <X11/Xos.h>
  32. #include <signal.h>
  33. #ifdef SIGNALRETURNSINT
  34. #define SIGVAL int
  35. #else
  36. #define SIGVAL void
  37. #endif
  38.  
  39. #include <math.h>
  40.  
  41. #include <X11/Xatom.h>
  42. #include <X11/Intrinsic.h>
  43. #include <X11/StringDefs.h>
  44. #include <X11/Shell.h>
  45. #include <X11/Xaw/Cardinals.h>
  46. #include <X11/Xaw/Form.h>
  47. #include <X11/Xaw/SimpleMenu.h>
  48. #include <X11/Xaw/SmeBSB.h>
  49. #include <X11/Xaw/SmeLine.h>
  50. #include <X11/Xaw/Scrollbar.h>
  51. #include <X11/Xaw/AsciiText.h>
  52. /* Yuck, cannot get vScrollbar via the usual methods */
  53. #include <X11/IntrinsicP.h>
  54. #include <X11/Xaw/TextP.h>
  55. #include <X11/Xmu/StdCmap.h>
  56.  
  57. #include <errno.h>
  58. /* BSD 4.3 errno.h does not declare errno */
  59. extern int errno;
  60. #ifdef VMS
  61. #include <perror.h>
  62. #else
  63. extern int sys_nerr;
  64. extern char *sys_errlist[];
  65. #endif
  66.  
  67. #include "Ghostview.h"
  68. #include "gv.h"
  69. #include "ps.h"
  70.  
  71. #ifndef max
  72. #define max(a, b)    ((a) > (b) ? (a) : (b))
  73. #endif
  74.  
  75. /* Translate orientations defined by the enum in "ps.h" to
  76.  * XtPageOrientations defined in "Ghostview.h".
  77.  */
  78. static XtPageOrientation
  79. xorient(psorient)
  80.     int psorient;
  81. {
  82.     switch (psorient) {
  83.     case PORTRAIT: return XtPageOrientationPortrait;
  84.     case LANDSCAPE:
  85.     if (app_res.swap_landscape) {
  86.         return XtPageOrientationSeascape;
  87.     } else {
  88.         return XtPageOrientationLandscape;
  89.     }
  90.     }
  91. }
  92.  
  93. static void
  94. break_chains()
  95. {
  96.     Arg args[2];
  97.     XtSetArg(args[0], XtNbottom, XtChainTop);
  98.     XtSetArg(args[1], XtNright, XtChainLeft);
  99.     XtSetValues(toc, args, ONE);
  100.     XtSetValues(pageview, args, TWO);
  101. }
  102.  
  103. static void
  104. set_chains()
  105. {
  106.     Arg args[2];
  107.  
  108.     XtSetArg(args[0], XtNbottom, XtChainBottom);
  109.     XtSetArg(args[1], XtNright, XtChainRight);
  110.     XtSetValues(toc, args, ONE);
  111.     XtSetValues(pageview, args, TWO);
  112. }
  113.  
  114. static void
  115. reset_size_hints()
  116. {
  117.     Arg args[4];
  118.     if (app_res.ncdwm) return;
  119.     XtSetArg(args[0], XtNmaxWidth, XtUnspecifiedShellInt);
  120.     XtSetArg(args[1], XtNmaxHeight, XtUnspecifiedShellInt);
  121.     XtSetArg(args[2], XtNminWidth, XtUnspecifiedShellInt);
  122.     XtSetArg(args[3], XtNminHeight, XtUnspecifiedShellInt);
  123.     XtSetValues(toplevel, args, FOUR);
  124. }
  125.  
  126. static void
  127. set_size_hints(minw, minh, maxw, maxh)
  128.     Dimension minw, minh, maxw, maxh;
  129. {
  130.     Arg args[4];
  131.  
  132.     XtSetArg(args[0], XtNminWidth, minw);
  133.     XtSetArg(args[1], XtNminHeight, minh);
  134.     XtSetArg(args[2], XtNmaxWidth, maxw);
  135.     XtSetArg(args[3], XtNmaxHeight, maxh);
  136.     XtSetValues(toplevel, args, FOUR);
  137. }
  138.  
  139. static Boolean horiz_scroll_saved = False;
  140. static Boolean vert_scroll_saved = False;
  141. static float horiz_top;
  142. static float vert_top;
  143.  
  144. static void
  145. reset_scroll_bars()
  146. {
  147.     Arg args[1];
  148.     Widget scroll;
  149.     float zero = 0.0;
  150.     
  151.     if (horiz_scroll_saved || vert_scroll_saved) return;
  152.  
  153.     scroll = XtNameToWidget(pageview, "horizontal");
  154.     if (scroll) {
  155.     XtSetArg(args[0], XtNtopOfThumb, &horiz_top);
  156.     XtGetValues(scroll, args, ONE);
  157.     XtCallCallbacks(scroll, XtNjumpProc, &zero);
  158.     horiz_scroll_saved = True;
  159.     }
  160.  
  161.     scroll = XtNameToWidget(pageview, "vertical");
  162.     if (scroll) {
  163.     XtSetArg(args[0], XtNtopOfThumb, &vert_top);
  164.     XtGetValues(scroll, args, ONE);
  165.     XtCallCallbacks(scroll, XtNjumpProc, &zero);
  166.     vert_scroll_saved = True;
  167.     }
  168. }
  169.  
  170. static void
  171. set_scroll_bars()
  172. {
  173.     Arg args[1];
  174.     Widget scroll;
  175.     float shown;
  176.  
  177.     if (horiz_scroll_saved) {
  178.     scroll = XtNameToWidget(pageview, "horizontal");
  179.     if (scroll) {
  180.         XtSetArg(args[0], XtNshown, &shown);
  181.         XtGetValues(scroll, args, ONE);
  182.         if (horiz_top > (1.0 - shown)) horiz_top = (1.0 - shown);
  183.         XtCallCallbacks(scroll, XtNjumpProc, &horiz_top);
  184.     }
  185.     }
  186.  
  187.     if (vert_scroll_saved) {
  188.     scroll = XtNameToWidget(pageview, "vertical");
  189.     if (scroll) {
  190.         XtSetArg(args[0], XtNshown, &shown);
  191.         XtGetValues(scroll, args, ONE);
  192.         if (vert_top > (1.0 - shown)) vert_top = (1.0 - shown);
  193.         XtCallCallbacks(scroll, XtNjumpProc, &vert_top);
  194.     }
  195.     }
  196.  
  197.     horiz_scroll_saved = vert_scroll_saved = False;
  198. }
  199.  
  200. /* Start rendering a new page */
  201. void
  202. show_page(number)
  203.     int number;
  204. {
  205.     struct stat sbuf;
  206.     int i;
  207.  
  208.     if (!filename) return;
  209.  
  210.     /* Unmark current_page as current */
  211.     if (toc_text && (current_page >= 0)) {
  212.     int marker = current_page*toc_entry_length + toc_entry_length-2;
  213.     toc_text[marker] = ' ';
  214.     XawTextInvalidate(toc, marker, marker+1);
  215.     }
  216.  
  217.     /* If the file has changed, rescan it so that offsets into the file
  218.      * are still correct.  If the file is rescanned, we must setup ghostview
  219.      * again.  Also, force a new copy of ghostscript to start. */
  220.     if (psfile) {
  221.     if (!stat(filename, &sbuf) && mtime != sbuf.st_mtime) {
  222.         fclose(psfile);
  223.         psfile = fopen(filename, "r");
  224.         mtime = sbuf.st_mtime;
  225.         if (oldfilename) XtFree(oldfilename);
  226.         oldfilename = XtNewString(filename);
  227.         new_file(number);
  228.     }
  229.     }
  230.  
  231.     /* Coerce page number to fall in range */
  232.     if (toc_text) {
  233.     if (number >= doc->numpages) number = doc->numpages - 1;
  234.     if (number < 0) number = 0;
  235.     }
  236.  
  237.     if (set_new_orientation(number) || set_new_pagemedia(number))
  238.     layout_ghostview();
  239.  
  240.     if (toc_text) {
  241.     int marker;
  242.     current_page = number;
  243.     XawTextUnsetSelection(toc);
  244.     XawTextSetInsertionPoint(toc, current_page * toc_entry_length);
  245.     marker = current_page*toc_entry_length + toc_entry_length-2;
  246.     toc_text[marker] = '<';
  247.     XawTextInvalidate(toc, marker, marker+1);
  248.     if (GhostviewIsInterpreterReady(page)) {
  249.         GhostviewNextPage(page);
  250.     } else {
  251.         GhostviewEnableInterpreter(page);
  252.         GhostviewSendPS(page, psfile, doc->beginprolog,
  253.                 doc->lenprolog, False);
  254.         GhostviewSendPS(page, psfile, doc->beginsetup,
  255.                 doc->lensetup, False);
  256.     }
  257.     if (doc->pageorder == DESCEND)
  258.         i = (doc->numpages - 1) - current_page;
  259.     else
  260.         i = current_page;
  261.     GhostviewSendPS(page, psfile, doc->pages[i].begin,
  262.             doc->pages[i].len, False);
  263.     } else {
  264.     if (!GhostviewIsInterpreterRunning(page))
  265.         GhostviewEnableInterpreter(page);
  266.     else if (GhostviewIsInterpreterReady(page))
  267.         GhostviewNextPage(page);
  268.     else
  269.         XBell(XtDisplay(page), 0);
  270.     }
  271.  
  272.     if (toc_text) {
  273.     XtSetSensitive(prevbutton, current_page != 0);
  274.     XtSetSensitive(nextbutton, current_page != doc->numpages-1);
  275.     XtSetSensitive(showbutton, True);
  276.     }
  277. }
  278.  
  279. /* setup ghostview.  This includes:
  280.  *  scanning the PostScript file,
  281.  *  setting the title and date labels,
  282.  *  building the pagemedia menu,
  283.  *  building the toc (table of contents)
  284.  *  sensitizing the appropriate menu buttons,
  285.  *  popping down and erasing the infotext popup.
  286.  */
  287.  
  288. static Boolean useful_page_labels;
  289. Boolean
  290. setup_ghostview()
  291. {
  292.     Arg args[20];
  293.     Cardinal num_args;
  294.     int oldtoc_entry_length;
  295.     char *tocp;
  296.     XawTextBlock message_block;
  297.     static String nothing = "";
  298.     String label;
  299.     Pixmap bitmap;
  300.  
  301.     /* Reset to a known state. */
  302.     psfree(olddoc);
  303.     olddoc = doc;
  304.     doc = NULL;
  305.     current_page = -1;
  306.     if (toc_text) XtFree(toc_text);
  307.     oldtoc_entry_length = toc_entry_length;
  308.     toc_text = NULL;
  309.  
  310.     /* Scan document and start setting things up */
  311.     if (psfile) doc = psscan(psfile);
  312.  
  313.     if (app_res.show_title) {
  314.     if (doc && doc->title) {
  315.         label = doc->title;
  316.         bitmap = menu16_bitmap;
  317.     } else {
  318.         if (filename) {
  319.         label = filename;
  320.         } else {
  321.         label = "";
  322.         }
  323.         bitmap = None;
  324.     }
  325.     XtSetArg(args[0], XtNlabel, label);
  326.     XtSetValues(titlebutton, args, ONE);
  327.     if (titlemenu) XtDestroyWidget(titlemenu);
  328.     titlemenu = build_label_menu(titlebutton, "title", label, bitmap);
  329.     }
  330.  
  331.     if (app_res.show_date) {
  332.     if (doc && doc->date) {
  333.         label = doc->date;
  334.         bitmap = menu16_bitmap;
  335.     } else {
  336.         if (psfile) {
  337.         label = ctime(&mtime);
  338.         } else {
  339.         label = "";
  340.         }
  341.         bitmap = None;
  342.     }
  343.     XtSetArg(args[0], XtNlabel, label);
  344.     XtSetValues(datebutton, args, ONE);
  345.     if (datemenu) XtDestroyWidget(datemenu);
  346.     datemenu = build_label_menu(datebutton, "date", label, bitmap);
  347.     }
  348.  
  349.     build_pagemedia_menu();
  350.  
  351.     /* Reset ghostscript and output messages popup */
  352.     if (!doc || !olddoc ||
  353.     strcmp(oldfilename, filename) ||
  354.     olddoc->beginprolog != doc->beginprolog ||
  355.     olddoc->endprolog != doc->endprolog ||
  356.     olddoc->beginsetup != doc->beginsetup ||
  357.     olddoc->endsetup != doc->endsetup) {
  358.  
  359.     GhostviewDisableInterpreter(page);
  360.     XtPopdown(infopopup);
  361.     info_up = False;
  362.     XtSetArg(args[0], XtNeditType, XawtextEdit);
  363.     XtSetArg(args[1], XtNinsertPosition, 0);
  364.     XtSetValues(infotext, args, TWO);
  365.     message_block.length = 0;
  366.     XawTextReplace(infotext, 0, info_length, &message_block);
  367.     info_length = 0;
  368.     XtSetArg(args[0], XtNeditType, XawtextRead);
  369.     XtSetValues(infotext, args, ONE);
  370.     }
  371.  
  372.     /* Build table of contents */
  373.     if (doc && (!doc->epsf && doc->numpages > 0 ||
  374.          doc->epsf && doc->numpages > 1)) {
  375.     int maxlen = 0;
  376.     int i, j;
  377.     useful_page_labels = False;
  378.  
  379.     if (doc->numpages == 1) useful_page_labels = True;
  380.     for (i = 1; i < doc->numpages; i++)
  381.         if (useful_page_labels = (useful_page_labels ||
  382.             strcmp(doc->pages[i-1].label, doc->pages[i].label))) break;
  383.     if (useful_page_labels) {
  384.         for (i = 0; i < doc->numpages; i++) 
  385.         maxlen = max(maxlen, strlen(doc->pages[i].label));
  386.     } else {
  387.         double x;
  388.         x = doc->numpages;
  389.         maxlen = log10(x) + 1;
  390.     }
  391.     toc_entry_length = maxlen + 3;
  392.     toc_length = doc->numpages * toc_entry_length - 1;
  393.     toc_text = XtMalloc(toc_length + 2); /* include final NULL */
  394.  
  395.     for (i = 0, tocp = toc_text; i < doc->numpages;
  396.          i++, tocp += toc_entry_length) {
  397.         if (useful_page_labels) {
  398.         if (doc->pageorder == DESCEND) {
  399.             j = (doc->numpages - 1) - i;
  400.         } else {
  401.             j = i;
  402.         }
  403.         sprintf(tocp, " %*s \n", maxlen, doc->pages[j].label);
  404.         } else {
  405.         sprintf(tocp, " %*d \n", maxlen, i+1);
  406.         }
  407.     }
  408.     toc_text[toc_length] = '\0';
  409.                                       num_args = 0;
  410.     XtSetArg(args[num_args], XtNfilename, NULL);          num_args++;
  411.     XtSetValues(page, args, num_args);
  412.     } else {
  413.     toc_length = 0;
  414.     toc_entry_length = 3;
  415.                                       num_args = 0;
  416.     XtSetArg(args[num_args], XtNfilename, filename);          num_args++;
  417.     XtSetValues(page, args, num_args);
  418.     }
  419.                                 num_args = 0;
  420.     XtSetArg(args[num_args], XtNlength, toc_length);        num_args++;
  421.     if (toc_text) {
  422.     XtSetArg(args[num_args], XtNstring, toc_text);        num_args++;
  423.     } else {
  424.     /* Text widget sometime blows up when given a NULL pointer */
  425.     XtSetArg(args[num_args], XtNstring, nothing);        num_args++;
  426.     }
  427.     XtSetValues(toc, args, num_args);
  428.  
  429.     XtSetSensitive(reopenbutton, (psfile != NULL));
  430.     XtSetSensitive(printwholebutton, (psfile != NULL));
  431.     XtSetSensitive(printmarkedbutton, (psfile != NULL));
  432.     XtSetSensitive(savebutton, (toc_text != NULL));
  433.     XtSetSensitive(nextbutton, (filename != NULL));
  434.     XtSetSensitive(showbutton, (filename != NULL));
  435.     XtSetSensitive(prevbutton, (toc_text != NULL));
  436.     XtSetSensitive(centerbutton, (filename != NULL));
  437.     XtSetSensitive(markbutton, (toc_text != NULL));
  438.     XtSetSensitive(unmarkbutton, (toc_text != NULL));
  439.  
  440.     return oldtoc_entry_length != toc_entry_length;
  441. }
  442.  
  443. int
  444. find_page(label)
  445.     String label;
  446. {
  447.     int i, j;
  448.  
  449.     if (label == NULL || doc == NULL) return 0;
  450.  
  451.     if (useful_page_labels) {
  452.     for (i = 0; i < doc->numpages; i++) {
  453.         if (doc->pageorder == DESCEND) {
  454.         j = (doc->numpages - 1) - i;
  455.         } else {
  456.         j = i;
  457.         }
  458.         if (!strcmp(label, doc->pages[j].label)) return i;
  459.     }
  460.     return 0;
  461.     } else {
  462.     return atoi(label) - 1;
  463.     }
  464. }
  465.  
  466. /* try_try_again sets the geometry of the form when the form failed
  467.  * to do it earlier.  It uses activity check with exponential backoff
  468.  * to make sure that the dust has settled before trying again.
  469.  */
  470. static unsigned int delay = 125;    /* Start with 1/8 second delay */
  471.  
  472. static void
  473. try_try_again(client_data, timer)
  474.     XtPointer client_data;
  475.     XtIntervalId *timer;
  476. {
  477.     XSync(XtDisplay(toplevel), False);    /* Push everything out */
  478.     if (XtAppPending(app_con)) {
  479.     XtAppAddTimeOut(app_con, delay, try_try_again, NULL);
  480.     /* fprintf(stderr, "Delaying(%d)...\n",delay); */
  481.     delay *= 2;
  482.     } else {
  483.     /* fprintf(stderr, "Trying again...\n"); */
  484.     layout_ghostview();
  485.     }
  486. }
  487.  
  488. /* set the dimensions for items in the main form widget. */
  489. /* set foreground and background color in scrollbars. */
  490. /* (The scroll bars come and go as size changes.) */
  491. /* Set window manager hints to keep window manager from causing main */
  492. /* viewport from growing too large */
  493. void
  494. layout_ghostview()
  495. {
  496.     Arg args[20];
  497.     Dimension min_width, min_height;
  498.     Dimension max_width, max_height;
  499.     Dimension form_width, form_height;
  500.     Dimension title_height, title_border;
  501.     Dimension date_height, date_border;
  502.     Dimension locator_height, locator_border;
  503.     Dimension box_width, box_height, box_border;
  504.     Dimension label_width;
  505.     Dimension toc_width, toc_height, toc_border;
  506.     Dimension view_width, view_height, view_border;
  507.     Dimension page_width, page_height;
  508.     Dimension leftMargin, rightMargin;
  509.     Dimension width, height;
  510.     Boolean correct = True;
  511.     int distance;
  512.     int a_label;
  513.     XFontStruct *font;
  514.  
  515.     XawFormDoLayout(form, False);
  516.     reset_size_hints();
  517.     reset_scroll_bars();
  518.     break_chains();
  519.  
  520.     XtSetArg(args[0], XtNdefaultDistance, &distance);
  521.     XtGetValues(form, args, ONE);
  522.  
  523.     a_label = 0;
  524.     if (app_res.show_title) {
  525.     XtSetArg(args[0], XtNheight, &title_height);
  526.     XtSetArg(args[1], XtNborderWidth, &title_border);
  527.     XtGetValues(titlebutton, args, TWO);
  528.     a_label = 1;
  529.     } else {
  530.     title_height = title_border = 0;
  531.     }
  532.  
  533.     if (app_res.show_date) {
  534.     XtSetArg(args[0], XtNheight, &date_height);
  535.     XtSetArg(args[1], XtNborderWidth, &date_border);
  536.     XtGetValues(datebutton, args, TWO);
  537.     a_label = 1;
  538.     } else {
  539.     date_height = date_border = 0;
  540.     }
  541.  
  542.     if (app_res.show_locator) {
  543.     XtSetArg(args[0], XtNheight, &locator_height);
  544.     XtSetArg(args[1], XtNborderWidth, &locator_border);
  545.     XtGetValues(locator, args, TWO);
  546.     a_label = 1;
  547.     } else {
  548.     locator_height = locator_border = 0;
  549.     }
  550.  
  551.     XtSetArg(args[0], XtNwidth, &box_width);
  552.     XtSetArg(args[1], XtNheight, &box_height);
  553.     XtSetArg(args[2], XtNborderWidth, &box_border);
  554.     XtGetValues(box, args, THREE);
  555.  
  556.     XtSetArg(args[0], XtNfont, &font);
  557.     XtSetArg(args[1], XtNleftMargin, &leftMargin);
  558.     XtSetArg(args[2], XtNrightMargin, &rightMargin);
  559.     XtSetArg(args[3], XtNborderWidth, &toc_border);
  560.     XtGetValues(toc, args, FOUR);
  561.     toc_width = font->max_bounds.width * (toc_entry_length - 1) +
  562.         leftMargin + rightMargin;
  563.  
  564.     XtSetArg(args[0], XtNwidth, &page_width);
  565.     XtSetArg(args[1], XtNheight, &page_height);
  566.     XtGetValues(page, args, TWO);
  567.  
  568.     XtSetArg(args[0], XtNborderWidth, &view_border);
  569.     XtGetValues(pageview, args, ONE);
  570.     view_width = page_width;
  571.     view_height = page_height;
  572.  
  573.     min_width = box_width + 2*box_border + toc_width + 2*toc_border +
  574.         2*view_border + 4*distance;
  575.     min_height = title_height + 2*title_border + date_height + 2*date_border +
  576.          locator_height + 2*locator_border + box_height + 2*box_border +
  577.          (2+a_label)*distance;
  578.  
  579.     max_width = WidthOfScreen(XtScreen(toplevel)) - app_res.wm_horiz_margin;
  580.     max_height = HeightOfScreen(XtScreen(toplevel)) - app_res.wm_vert_margin;
  581.  
  582.     if (min_width + view_width > max_width)
  583.     view_width = max_width - min_width;
  584.     if (2*(view_border + distance) + view_height > max_height)
  585.     view_height = max_height - 2*(view_border + distance);
  586.     form_width = view_width + min_width;
  587.     form_height = max(view_height + 2*(view_border + distance), min_height);
  588.     toc_height = view_height - (title_height + 2*title_border +
  589.                 date_height + 2*date_border +
  590.                 locator_height + 2*locator_border +
  591.                 a_label*distance);
  592.  
  593.     label_width = box_width + 2*box_border + distance +
  594.           toc_width + 2*toc_border;
  595.  
  596.     XtSetArg(args[0], XtNwidth, form_width);
  597.     XtSetArg(args[1], XtNheight, form_height);
  598.     XtSetValues(form, args, TWO);
  599.  
  600.     XtSetArg(args[0], XtNwidth, label_width);
  601.     if (app_res.show_title) XtSetValues(titlebutton, args, ONE);
  602.     if (app_res.show_date) XtSetValues(datebutton, args, ONE);
  603.     if (app_res.show_locator) XtSetValues(locator, args, ONE);
  604.  
  605.     XtSetArg(args[0], XtNwidth, toc_width);
  606.     XtSetArg(args[1], XtNheight, toc_height);
  607.     XtSetValues(toc, args, TWO);
  608.  
  609.     XtSetArg(args[0], XtNwidth, view_width);
  610.     XtSetArg(args[1], XtNheight, view_height);
  611.     XtSetValues(pageview, args, TWO);
  612.  
  613.     XawFormDoLayout(form, True);
  614.  
  615.     /* Check to make sure everything was done as planned. */
  616.     XtSetArg(args[0], XtNwidth, &width);
  617.     XtSetArg(args[1], XtNheight, &height);
  618.  
  619.     XtGetValues(form, args, TWO);
  620.     if (width != form_width || height != form_height) {
  621.     correct = False;
  622.     /* fprintf(stderr, "Oops, %dx%d form was supposed to be %dx%d.\n",
  623.         width, height, form_width, form_height); */
  624.     }
  625.     if (app_res.show_title) {
  626.     XtGetValues(titlebutton, args, ONE);
  627.     if (width != label_width) {
  628.         correct = False;
  629.         /* fprintf(stderr,
  630.         "Oops, %d wide title was supposed to be %d wide.\n",
  631.         width, label_width); */
  632.     }
  633.     }
  634.     if (app_res.show_date) {
  635.     XtGetValues(datebutton, args, ONE);
  636.     if (width != label_width) {
  637.         correct = False;
  638.         /* fprintf(stderr,
  639.         "Oops, %d wide date was supposed to be %d wide.\n",
  640.         width, label_width); */
  641.     }
  642.     }
  643.     if (app_res.show_locator) {
  644.     XtGetValues(locator, args, ONE);
  645.     if (width != label_width) {
  646.         correct = False;
  647.         /* fprintf(stderr,
  648.         "Oops, %d wide locator was supposed to be %d wide.\n",
  649.         width, label_width); */
  650.     }
  651.     }
  652.     XtGetValues(toc, args, TWO);
  653.     if (width != toc_width || height != toc_height) {
  654.     correct = False;
  655.     /* fprintf(stderr, "Oops, %dx%d toc was supposed to be %dx%d.\n",
  656.         width, height, toc_width, toc_height); */
  657.     }
  658.     XtGetValues(pageview, args, TWO);
  659.     if (width != view_width || height != view_height) {
  660.     correct = False;
  661.     /* fprintf(stderr, "Oops, %dx%d pageview was supposed to be %dx%d.\n",
  662.         width, height, view_width, view_height); */
  663.     }
  664.  
  665.     if (correct) {
  666.     set_size_hints(min_width, min_height, min_width+page_width,
  667.                max(form_height,
  668.                page_height + 2*(view_border + distance)));
  669.     if (app_res.auto_center) {
  670.         horiz_scroll_saved = vert_scroll_saved = False;
  671.         center_page(form, NULL, NULL);
  672.     } else {
  673.         set_scroll_bars();
  674.     }
  675.     set_chains();
  676.     delay = 125;    /* Reset to 1/8 second delay */
  677.     /* fprintf(stderr, "Layout correct.\n"); */
  678.     } else {
  679.     XSync(XtDisplay(toplevel), False);
  680.     XtAppAddTimeOut(app_con, delay, try_try_again, NULL);
  681.     /* fprintf(stderr, "Didn't work, scheduling(%d)...\n",delay); */
  682.     }
  683.  
  684. }
  685.  
  686. /* Compute new dpi from magstep */
  687. void
  688. magnify(dpi, magstep)
  689.     float *dpi;
  690.     int    magstep;
  691. {
  692.     if (magstep < 0) {
  693.     while (magstep++) *dpi /= 1.2;
  694.     } else {
  695.     while (magstep--) *dpi *= 1.2;
  696.     }
  697. }
  698.  
  699. /* Attempt to open file, return error message string on failure */
  700. String
  701. open_file(name)
  702.     String name;
  703. {
  704.     FILE *fp;
  705.     struct stat sbuf;
  706.  
  707.     if (*name == '\0') {    /* Null filename */
  708.     return(NULL);
  709.     }
  710.     if (strcmp(name, "-")) {
  711.     if ((fp = fopen(name, "r")) == NULL) {
  712.         String buf = XtMalloc(strlen(app_res.open_fail) +
  713.                   strlen(sys_errlist[errno]) + 1);
  714.         strcpy(buf, app_res.open_fail);
  715.         if (errno <= sys_nerr) strcat(buf, sys_errlist[errno]);
  716.         return buf;
  717.     } else {
  718.         if (oldfilename) XtFree(oldfilename);
  719.         oldfilename = filename;
  720.         filename = XtNewString(name);
  721.         if (psfile) fclose(psfile);
  722.         psfile = fp;
  723.         stat(filename, &sbuf);
  724.         mtime = sbuf.st_mtime;
  725.         new_file(0);
  726.         show_page(0);
  727.         return(NULL);
  728.     }
  729.     } else {
  730.     if (oldfilename) XtFree(oldfilename);
  731.     oldfilename = filename;
  732.     filename = XtNewString(name);
  733.     if (psfile) fclose(psfile);
  734.     psfile = NULL;
  735.     new_file(0);
  736.     show_page(0);
  737.     return(NULL);
  738.     }
  739. }
  740.  
  741. /* Attempt to save file, return error message string on failure */
  742. String
  743. save_file(name)
  744.     String name;
  745. {
  746.     FILE *pswrite;
  747.  
  748.     if (*name == '\0') {    /* Null filename */
  749.     return(NULL);
  750.     }
  751.     if ((pswrite = fopen(name, "w")) == NULL) {
  752.     String buf = XtMalloc(strlen(app_res.save_fail) +
  753.                   strlen(sys_errlist[errno]) + 1);
  754.     strcpy(buf, app_res.save_fail);
  755.     if (errno <= sys_nerr) strcat(buf, sys_errlist[errno]);
  756.     return buf;
  757.     } else {
  758.     pscopydoc(pswrite);
  759.     fclose(pswrite);
  760.     return(NULL);
  761.     }
  762. }
  763.  
  764. /* Attempt to print file.  Return error string on failure */ 
  765. String
  766. print_file(name, whole_mode)
  767.     String name;
  768.     Boolean whole_mode;
  769. {
  770.     FILE *printer;
  771.     SIGVAL (*oldsig)();
  772.     int bytes;
  773.     char buf[BUFSIZ];
  774. #ifdef VMS
  775.     char fnam[64], *p;
  776. #endif
  777.     Boolean failed;
  778.     String ret_val;
  779.  
  780. #ifdef VMS
  781.     sprintf(fnam, "sys$scratch:%s.tmp", tmpnam(NULL));
  782.     printer = fopen(fnam, "w");
  783. #else /* VMS */
  784.     if (*name != '\0') {
  785.     setenv(app_res.printer_variable, name, True);
  786.     }
  787.     oldsig = signal(SIGPIPE, SIG_IGN);
  788.     printer = popen(app_res.print_command, "w");
  789. #endif /* VMS */
  790.     if (toc_text && !whole_mode) {
  791.     pscopydoc(printer);
  792.     } else {
  793.     FILE *psfile = fopen(filename, "r");
  794.     while (bytes = read(fileno(psfile), buf, BUFSIZ))
  795.         bytes = write(fileno(printer), buf, bytes);
  796.     fclose(psfile);
  797.     }
  798. #ifdef VMS
  799.     sprintf(buf, "%s %s %s", app_res.print_command, name, fnam);
  800.     failed = fclose(printer) != 0 || system(buf) != 1;
  801. #else /* VMS */
  802.     failed = pclose(printer) != 0;
  803. #endif /* VMS */
  804.     if (failed) {
  805.     sprintf(buf, app_res.print_fail, app_res.print_command);
  806.     ret_val = XtNewString(buf);
  807.     } else {
  808.     ret_val = NULL;
  809.     }
  810. #ifndef VMS
  811.     signal(SIGPIPE, oldsig);
  812. #endif /* VMS */
  813.     return(ret_val);
  814. }
  815.  
  816. /* length calculates string length at compile time */
  817. /* can only be used with character constants */
  818. #define length(a) (sizeof(a)-1)
  819.  
  820. /* Copy the headers, marked pages, and trailer to fp */
  821. void
  822. pscopydoc(fp)
  823.     FILE *fp;
  824. {
  825.     FILE *psfile;
  826.     char text[PSLINELENGTH];
  827.     char *comment;
  828.     Boolean pages_written = False;
  829.     Boolean pages_atend = False;
  830.     Boolean marked_pages = False;
  831.     int pages = 0;
  832.     int page = 1;
  833.     int i, j;
  834.     long here;
  835.  
  836.     psfile = fopen(filename, "r");
  837.  
  838.     for (i = 0; i < doc->numpages; i++) {
  839.     if (toc_text[toc_entry_length * i] == '*') pages++;
  840.     }
  841.  
  842.     if (pages == 0) {    /* User forgot to mark the pages */
  843.     mark_page(form, NULL, NULL);
  844.     marked_pages = True;
  845.     for (i = 0; i < doc->numpages; i++) {
  846.         if (toc_text[toc_entry_length * i] == '*') pages++;
  847.     }
  848.     }
  849.  
  850.     here = doc->beginheader;
  851.     while (comment = pscopyuntil(psfile, fp, here,
  852.                  doc->endheader, "%%Pages:")) {
  853.     here = ftell(psfile);
  854.     if (pages_written || pages_atend) {
  855.         free(comment);
  856.         continue;
  857.     }
  858.     sscanf(comment+length("%%Pages:"), "%s", text);
  859.     if (strcmp(text, "(atend)") == 0) {
  860.         fputs(comment, fp);
  861.         pages_atend = True;
  862.     } else {
  863.         switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  864.         case 1:
  865.             fprintf(fp, "%%%%Pages: %d %d\n", pages, i);
  866.             break;
  867.         default:
  868.             fprintf(fp, "%%%%Pages: %d\n", pages);
  869.             break;
  870.         }
  871.         pages_written = True;
  872.     }
  873.     free(comment);
  874.     }
  875.     pscopy(psfile, fp, doc->beginpreview, doc->endpreview);
  876.     pscopy(psfile, fp, doc->begindefaults, doc->enddefaults);
  877.     pscopy(psfile, fp, doc->beginprolog, doc->endprolog);
  878.     pscopy(psfile, fp, doc->beginsetup, doc->endsetup);
  879.  
  880.     for (i = 0; i < doc->numpages; i++) {
  881.     if (doc->pageorder == DESCEND) 
  882.         j = (doc->numpages - 1) - i;
  883.     else
  884.         j = i;
  885.     if (toc_text[toc_entry_length * j] == '*') {
  886.         comment = pscopyuntil(psfile, fp, doc->pages[i].begin,
  887.                   doc->pages[i].end, "%%Page:");
  888.         fprintf(fp, "%%%%Page: %s %d\n",
  889.             doc->pages[i].label, page++);
  890.         free(comment);
  891.         pscopy(psfile, fp, -1, doc->pages[i].end);
  892.     }
  893.     }
  894.  
  895.     here = doc->begintrailer;
  896.     while (comment = pscopyuntil(psfile, fp, here,
  897.                  doc->endtrailer, "%%Pages:")) {
  898.     here = ftell(psfile);
  899.     if (pages_written) {
  900.         free(comment);
  901.         continue;
  902.     }
  903.     switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  904.         case 1:
  905.         fprintf(fp, "%%%%Pages: %d %d\n", pages, i);
  906.         break;
  907.         default:
  908.         fprintf(fp, "%%%%Pages: %d\n", pages);
  909.         break;
  910.     }
  911.     pages_written = True;
  912.     free(comment);
  913.     }
  914.     fclose(psfile);
  915.  
  916.     if (marked_pages) unmark_page(form, NULL, NULL);
  917. }
  918. #undef length
  919.  
  920. /* position popup window under the cursor */
  921. void
  922. positionpopup(w)
  923.     Widget w;
  924. {
  925.     Arg args[3];
  926.     Cardinal num_args;
  927.     Dimension width, height, b_width;
  928.     int x, y, max_x, max_y;
  929.     Window root, child;
  930.     int dummyx, dummyy;
  931.     unsigned int dummymask;
  932.     
  933.     XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &x, &y,
  934.           &dummyx, &dummyy, &dummymask);
  935.     num_args = 0;
  936.     XtSetArg(args[num_args], XtNwidth, &width); num_args++;
  937.     XtSetArg(args[num_args], XtNheight, &height); num_args++;
  938.     XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
  939.     XtGetValues(w, args, num_args);
  940.  
  941.     width += 2 * b_width;
  942.     height += 2 * b_width;
  943.  
  944.     x -= ( (Position) width/2 );
  945.     if (x < 0) x = 0;
  946.     if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
  947.  
  948.     y -= ( (Position) height/2 );
  949.     if (y < 0) y = 0;
  950.     if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
  951.     
  952.     num_args = 0;
  953.     XtSetArg(args[num_args], XtNx, x); num_args++;
  954.     XtSetArg(args[num_args], XtNy, y); num_args++;
  955.     XtSetValues(w, args, num_args);
  956. }
  957.  
  958. /* Set new magstep */
  959. Boolean
  960. set_new_magstep()
  961. {
  962.     int new_magstep;
  963.     Boolean changed = False;
  964.     Arg args[20];
  965.     Cardinal num_args;
  966.     float xdpi, ydpi;
  967.  
  968.     new_magstep = app_res.magstep;
  969.     /* If magstep changed, stop interpreter and setup for new dpi. */
  970.     if (new_magstep != current_magstep) {
  971.     GhostviewDisableInterpreter(page);
  972.     XawFormDoLayout(form, False);
  973.     reset_size_hints();
  974.     reset_scroll_bars();
  975.     break_chains();
  976.     changed = True;
  977.     xdpi = default_xdpi;
  978.     ydpi = default_ydpi;
  979.     magnify(&xdpi, new_magstep);
  980.     magnify(&ydpi, new_magstep);
  981.                             num_args = 0;
  982.     XtSetFloatArg(args[num_args], XtNxdpi, xdpi);    num_args++;
  983.     XtSetFloatArg(args[num_args], XtNydpi, ydpi);    num_args++;
  984.     XtSetValues(page, args, num_args);
  985.  
  986.     XtSetArg(args[0], XtNleftBitmap, None);
  987.     XtSetValues(magstepentry[current_magstep - app_res.minimum_magstep],
  988.             args, ONE);
  989.     current_magstep = new_magstep;
  990.     }
  991.     XtSetArg(args[0], XtNleftBitmap, dot_bitmap);
  992.     XtSetValues(magstepentry[current_magstep - app_res.minimum_magstep],
  993.         args, ONE);
  994.  
  995.     return changed;
  996. }
  997.  
  998. /* Set new orientation */
  999. Boolean
  1000. set_new_orientation(number)
  1001.     int number;
  1002. {
  1003.     Boolean changed = False;
  1004.     Boolean from_doc = False;
  1005.     Arg args[1];
  1006.     XtPageOrientation new_orientation;
  1007.  
  1008.     if (app_res.force_orientation) {
  1009.     new_orientation = app_res.orientation;
  1010.     } else {
  1011.     if (doc) {
  1012.         if (toc_text && doc->pages[number].orientation != NONE) {
  1013.         new_orientation = xorient(doc->pages[number].orientation);
  1014.         from_doc = True;
  1015.         } else if (doc->default_page_orientation != NONE) {
  1016.         new_orientation = xorient(doc->default_page_orientation);
  1017.         from_doc = True;
  1018.         } else if (doc->orientation != NONE) {
  1019.         new_orientation = xorient(doc->orientation);
  1020.         from_doc = True;
  1021.         } else {
  1022.         new_orientation = app_res.orientation;
  1023.         }
  1024.     } else {
  1025.         new_orientation = app_res.orientation;
  1026.     }
  1027.     }
  1028.  
  1029.     /* If orientation changed,
  1030.      * stop interpreter and setup for new orientation. */
  1031.     if (new_orientation != current_orientation) {
  1032.     GhostviewDisableInterpreter(page);
  1033.     XawFormDoLayout(form, False);
  1034.     reset_size_hints();
  1035.     reset_scroll_bars();
  1036.     break_chains();
  1037.     changed = True;
  1038.     XtSetArg(args[0], XtNorientation, new_orientation);
  1039.     XtSetValues(page, args, ONE);
  1040.     XtSetArg(args[0], XtNleftBitmap, None);
  1041.     if (current_orientation == XtPageOrientationPortrait) 
  1042.         XtSetValues(portraitbutton, args, ONE);
  1043.     else if (current_orientation == XtPageOrientationLandscape)
  1044.             XtSetValues(landscapebutton, args, ONE);
  1045.         else if (current_orientation == XtPageOrientationUpsideDown)
  1046.             XtSetValues(upsidedownbutton, args, ONE);
  1047.         else if (current_orientation == XtPageOrientationSeascape)
  1048.             XtSetValues(seascapebutton, args, ONE);
  1049.     current_orientation = new_orientation;
  1050.     }
  1051.  
  1052.     /* mark forced orientation with tie fighter. ("Use the force, Luke") */
  1053.     if (app_res.force_orientation) {
  1054.     XtSetArg(args[0], XtNleftBitmap, tie_fighter_bitmap);
  1055.     } else if (from_doc) {
  1056.     XtSetArg(args[0], XtNleftBitmap, menu16_bitmap);
  1057.     } else {
  1058.     XtSetArg(args[0], XtNleftBitmap, dot_bitmap);
  1059.     }
  1060.     if (current_orientation == XtPageOrientationPortrait) 
  1061.     XtSetValues(portraitbutton, args, ONE);
  1062.     else if (current_orientation == XtPageOrientationLandscape)
  1063.     XtSetValues(landscapebutton, args, ONE);
  1064.     else if (current_orientation == XtPageOrientationUpsideDown)
  1065.     XtSetValues(upsidedownbutton, args, ONE);
  1066.     else if (current_orientation == XtPageOrientationSeascape)
  1067.     XtSetValues(seascapebutton, args, ONE);
  1068.     
  1069.     return changed;
  1070. }
  1071.  
  1072. /* Set new pagemedia */
  1073. Boolean
  1074. set_new_pagemedia(number)
  1075.     int number;
  1076. {
  1077.     int new_pagemedia;
  1078.     int new_llx;
  1079.     int new_lly;
  1080.     int new_urx;
  1081.     int new_ury;
  1082.     Boolean changed = False;
  1083.     Boolean from_doc = False;
  1084.     Arg args[4];
  1085.  
  1086.     if (force_document_media) {
  1087.     new_pagemedia = document_media;
  1088.     } else if (app_res.force_pagemedia) {
  1089.     new_pagemedia = default_pagemedia;
  1090.     } else {
  1091.     if (doc) {
  1092.         if (toc_text && doc->pages[number].media != NULL) {
  1093.         new_pagemedia = doc->pages[number].media - doc->media;
  1094.         from_doc = True;
  1095.         } else if (doc->default_page_media != NULL) {
  1096.         new_pagemedia = doc->default_page_media - doc->media;
  1097.         from_doc = True;
  1098.         } else {
  1099.         new_pagemedia = default_pagemedia;
  1100.         }
  1101.     } else {
  1102.         new_pagemedia = default_pagemedia;
  1103.     }
  1104.     }
  1105.  
  1106.     /* If pagemedia changed, remove the old marker. */
  1107.     if (new_pagemedia != current_pagemedia) {
  1108.     XtSetArg(args[0], XtNleftBitmap, None);
  1109.     if (pagemediaentry[current_pagemedia])
  1110.         XtSetValues(pagemediaentry[current_pagemedia], args, ONE);
  1111.     else
  1112.         XtSetValues(pagemediaentry[current_pagemedia-1], args, ONE);
  1113.  
  1114.     current_pagemedia = new_pagemedia;
  1115.     }
  1116.  
  1117.     /* mark forced page media with tie fighter. ("Use the force, Luke") */
  1118.     if (force_document_media || app_res.force_pagemedia) {
  1119.     XtSetArg(args[0], XtNleftBitmap, tie_fighter_bitmap);
  1120.     } else if (from_doc) {
  1121.     XtSetArg(args[0], XtNleftBitmap, menu16_bitmap);
  1122.     } else {
  1123.     XtSetArg(args[0], XtNleftBitmap, dot_bitmap);
  1124.     }
  1125.     if (pagemediaentry[current_pagemedia])
  1126.     XtSetValues(pagemediaentry[current_pagemedia], args, ONE);
  1127.     else
  1128.     XtSetValues(pagemediaentry[current_pagemedia-1], args, ONE);
  1129.  
  1130.     /* Compute bounding box */
  1131.     if (!force_document_media && !app_res.force_pagemedia &&
  1132.     doc && doc->epsf &&
  1133.     /* Ignore malformed bounding boxes */
  1134.     (doc->boundingbox[URX] > doc->boundingbox[LLX]) &&
  1135.     (doc->boundingbox[URY] > doc->boundingbox[LLY])) {
  1136.     new_llx = doc->boundingbox[LLX];
  1137.     new_lly = doc->boundingbox[LLY];
  1138.     new_urx = doc->boundingbox[URX];
  1139.     new_ury = doc->boundingbox[URY];
  1140.     } else {
  1141.     new_llx = new_lly = 0;
  1142.     if (new_pagemedia < base_papersize) {
  1143.         new_urx = doc->media[new_pagemedia].width;
  1144.         new_ury = doc->media[new_pagemedia].height;
  1145.     } else {
  1146.         new_urx = papersizes[new_pagemedia-base_papersize].width;
  1147.         new_ury = papersizes[new_pagemedia-base_papersize].height;
  1148.     }
  1149.     }
  1150.  
  1151.     /* If bounding box changed, setup for new size. */
  1152.     if ((new_llx != current_llx) || (new_lly != current_lly) ||
  1153.     (new_urx != current_urx) || (new_ury != current_ury)) {
  1154.     GhostviewDisableInterpreter(page);
  1155.     XawFormDoLayout(form, False);
  1156.     reset_size_hints();
  1157.     reset_scroll_bars();
  1158.     break_chains();
  1159.     changed = True;
  1160.     current_llx = new_llx;
  1161.     current_lly = new_lly;
  1162.     current_urx = new_urx;
  1163.     current_ury = new_ury;
  1164.     XtSetArg(args[0], XtNllx, current_llx);
  1165.     XtSetArg(args[1], XtNlly, current_lly);
  1166.     XtSetArg(args[2], XtNurx, current_urx);
  1167.     XtSetArg(args[3], XtNury, current_ury);
  1168.     XtSetValues(page, args, FOUR);
  1169.     }
  1170.  
  1171.     return changed;
  1172. }
  1173.  
  1174. static Boolean
  1175. same_document_media()
  1176. {
  1177.     int i;
  1178.  
  1179.     if (olddoc == NULL && doc == NULL) return True;
  1180.     if (olddoc == NULL || doc == NULL) return False;
  1181.     if (olddoc->nummedia != doc->nummedia) return False;
  1182.     for (i = 0; i < doc->nummedia; i++)
  1183.     if (strcmp(olddoc->media[i].name, doc->media[i].name)) return False;
  1184.     return True;
  1185. }
  1186.  
  1187. void
  1188. build_pagemedia_menu()
  1189. {
  1190.     Arg args[20];
  1191.     Cardinal num_args;
  1192.     Widget w;
  1193.     int i;
  1194.  
  1195.     if (pagemediamenu && same_document_media()) return;
  1196.     if (pagemediamenu) XtDestroyWidget(pagemediamenu);
  1197.     force_document_media = False;
  1198.  
  1199.     pagemediamenu = XtCreatePopupShell("menu", simpleMenuWidgetClass,
  1200.                        pagemediabutton, NULL, ZERO);
  1201.  
  1202.     /* Build the Page Media menu */
  1203.     /* the Page media menu has two parts.
  1204.      *  - the document defined page medias
  1205.      *  - the standard page media defined from Adobe's PPD
  1206.      */
  1207.     base_papersize = 0;
  1208.     if (doc) base_papersize = doc->nummedia;
  1209.     for (i = 0; papersizes[i].name; i++) {}    /* Count the standard entries */
  1210.     i += base_papersize;
  1211.     pagemediaentry = (Widget *) XtMalloc(i * sizeof(Widget));
  1212.  
  1213.     if (doc && doc->nummedia) {
  1214.     for (i = 0; i < doc->nummedia; i++) {
  1215.                                 num_args = 0;
  1216.         XtSetArg(args[num_args], XtNleftMargin, 20);    num_args++;
  1217.         pagemediaentry[i] = XtCreateManagedWidget(doc->media[i].name,
  1218.                 smeBSBObjectClass, pagemediamenu,
  1219.                 args, num_args);
  1220.         XtAddCallback(pagemediaentry[i], XtNcallback,
  1221.               set_pagemedia, (XtPointer)i);
  1222.     }
  1223.  
  1224.                             num_args = 0;
  1225.     w = XtCreateManagedWidget("line", smeLineObjectClass, pagemediamenu,
  1226.                   args, num_args);
  1227.     }
  1228.  
  1229.     for (i = 0; papersizes[i].name; i++) {
  1230.     pagemediaentry[i+base_papersize] = NULL;
  1231.     if (i > 0) {
  1232.         /* Skip over same paper size with small imageable area */
  1233.         if ((papersizes[i].width == papersizes[i-1].width) &&
  1234.         (papersizes[i].height == papersizes[i-1].height)) {
  1235.         continue;
  1236.         }
  1237.     }
  1238.                             num_args = 0;
  1239.     XtSetArg(args[num_args], XtNleftMargin, 20);    num_args++;
  1240.     pagemediaentry[i+base_papersize] = XtCreateManagedWidget(
  1241.                         papersizes[i].name,
  1242.                         smeBSBObjectClass, pagemediamenu,
  1243.                         args, num_args);
  1244.     XtAddCallback(pagemediaentry[i+base_papersize], XtNcallback,
  1245.               set_pagemedia, (XtPointer)(i+base_papersize));
  1246.     }
  1247. }
  1248.  
  1249. Widget
  1250. build_label_menu(parent, name, label, bitmap)
  1251.     Widget parent;
  1252.     String name, label;
  1253.     Pixmap bitmap;
  1254. {
  1255.     Arg args[20];
  1256.     Cardinal num_args;
  1257.     Widget menu, entry;
  1258.                                 num_args = 0;
  1259.     menu = XtCreatePopupShell("menu", simpleMenuWidgetClass,
  1260.                   parent, args, num_args);
  1261.  
  1262.                                 num_args = 0;
  1263.     XtSetArg(args[num_args], XtNlabel, label);        num_args++;
  1264.     if (bitmap) {
  1265.         XtSetArg(args[num_args], XtNleftMargin, 20);    num_args++;
  1266.         XtSetArg(args[num_args], XtNleftBitmap, bitmap);    num_args++;
  1267.     }
  1268.     entry = XtCreateManagedWidget(name, smeBSBObjectClass,
  1269.                       menu, args, num_args);
  1270.     return menu;
  1271. }
  1272.  
  1273. void
  1274. new_file(number)
  1275.     int number;
  1276. {
  1277.     Boolean layout_changed = False;
  1278.  
  1279.     if (setup_ghostview()) layout_changed = True;
  1280.  
  1281.     /* Coerce page number to fall in range */
  1282.     if (toc_text) {
  1283.     if (number >= doc->numpages) number = doc->numpages - 1;
  1284.     if (number < 0) number = 0;
  1285.     }
  1286.  
  1287.     if (set_new_orientation(number)) layout_changed = True;
  1288.     if (set_new_pagemedia(number)) layout_changed = True;
  1289.     if (layout_changed) layout_ghostview();
  1290. }
  1291.  
  1292. /* Catch X errors die gracefully if one occurs */
  1293. int
  1294. catch_Xerror(dpy, err)
  1295.     Display *dpy;
  1296.     XErrorEvent *err;
  1297. {
  1298.     if (err->error_code == BadImplementation) {
  1299.     old_Xerror(dpy, err);
  1300.     return 0;
  1301.     }
  1302.     if (dying) return 0;
  1303.     dying = True;
  1304.     bomb = *err;
  1305.     XtDestroyWidget(toplevel);
  1306.     return 0;
  1307. }
  1308.